#include "bsp_spi_flash_w25qxx.h"



/* 定义IO = 1和 0的代码  */
#define SPI_CS_1()		W25QXX_CS_PORT->BSRR = W25QXX_CS_PIN
#define SPI_CS_0()		W25QXX_CS_PORT->BSRR = W25QXX_CS_PIN << 16;

#define SPI_SCK_1()		W25QXX_SCK_PORT->BSRR = W25QXX_SCK_PIN
#define SPI_SCK_0()		W25QXX_SCK_PORT->BSRR = W25QXX_SCK_PIN << 16;

#define SPI_MOSI_1()	W25QXX_MOSI_PORT->BSRR = W25QXX_MOSI_PIN
#define SPI_MOSI_0()	W25QXX_MOSI_PORT->BSRR = W25QXX_MOSI_PIN << 16;

#define SPI_MISO_READ()  ((W25QXX_MISO_PORT->IDR & W25QXX_MISO_PIN) != 0)

#define _CPOL     1
#define _CPHA     1
#define WAIT_TIME 1

/* 是否启用模拟 SPI */
#define USE_SIMULATE_SPI		1

//------------------------------------内部函数------------------------------------//
static uint8_t SPI_SendByte(uint8_t Byte);  // SPI 写函数

static void SPI_Delay(void);                // SPI 延时函数

/************* W25QXX函数 ****************/
#define W25Q_CS_1() SPI_CS_1()
#define W25Q_CS_0() SPI_CS_0()

#define _W25Q_DEBUG			1
#define W25Q_DEBUG_PRINTF(fmt,arg...)		do{\
											if(_W25Q_DEBUG)\
												printf("<<-FLASH-DEBUG->> < %s >[%d]\n"fmt"\n",__FILE__,__LINE__, ##arg);\
											}while(0)


#define Adjust 12
static void HAL_Delay_us(uint32_t us, uint16_t CLK_MHz )
{
    uint32_t Delay = us * CLK_MHz / Adjust;
    do
    {
        __NOP();
    } while (Delay --);
}


/*
 * MODE 0:CPOL=0，CPHA=0：此时空闲态时，SCLK处于低电平，数据采样是在第 1个边沿，	\
 * 			也就是 SCLK由低电平到高电平的跳变，所以数据采样是在上升沿，数据切换是在下降沿(第 2个边沿)。
 * MODE 1:CPOL=0，CPHA=1：此时空闲态时，SCLK处于低电平，数据采样是在第 2个边沿，	\
 * 			也就是 SCLK由高电平到低电平的跳变，所以数据采样是在下降沿，数据切换是在上升沿(第 1个边沿)。
 * MODE 2:CPOL=1，CPHA=0：此时空闲态时，SCLK处于高电平，数据采样是在第 1个边沿，	\
 * 			也就是 SCLK由高电平到低电平的跳变，所以数据采集是在下降沿，数据切换是在上升沿(第 2个边沿)。
 * MODE 3:CPOL=1，CPHA=1：此时空闲态时，SCLK处于高电平，数据采样是在第 2个边沿，	\
 * 			也就是 SCLK由低电平到高电平的跳变，所以数据采集是在上升沿，数据切换是在下降沿(第 1个边沿)。
*/

void bsp_spi_flash_w25qxx_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 打开GPIO时钟 */
    RCC_AHB1PeriphClockCmd(RCC_W25QXX_PORT, ENABLE);

    /* 配置为开漏输出 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;		/* 设为输出口 */
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 	

    GPIO_InitStructure.GPIO_Pin = W25QXX_CS_PIN;
    GPIO_Init(W25QXX_CS_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = W25QXX_SCK_PIN;
    GPIO_Init(W25QXX_SCK_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = W25QXX_MOSI_PIN;
    GPIO_Init(W25QXX_MOSI_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;		/* 设为输出口 */
    GPIO_InitStructure.GPIO_Pin = W25QXX_MISO_PIN;
    GPIO_Init(W25QXX_MISO_PORT, &GPIO_InitStructure);

    SPI_CS_1();
    SPI_SCK_1();
    SPI_MOSI_1();
}




/************************************************
函数名称 ： SPI_Flash_SendByte
功    能 ： 使用SPI发送/ 返回一个字节的数据
参    数 ： wData ---- 写数据
返 回 值 ： rData ---- 读数据
*************************************************/
static uint8_t SPI_Flash_SendByte( uint8_t wData )
{
	
#if USE_SIMULATE_SPI
	return SPI_SendByte(wData);
	
#else

		
#endif /* USE_SIMULATE_SPI */
}


/************************************************
函数名称 ： W25Qxx_Busy_Wait
功    能 ： W25Qxx忙等待
参    数 ： 无
返 回 值 ： 无
*************************************************/
static void W25Qxx_Busy_Wait(void)
{
	uint8_t flash_status = 0;
	
    W25Q_CS_0();
	
	SPI_Flash_SendByte(W25Q_STATUS_REG1);
	
	do
	{
		flash_status = SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	}while(flash_status & BIT_BUSY);
	
    W25Q_CS_1();
}


/************************************************
函数名称 ： W25Qxx_Read_JEDECID
功    能 ： 读 W25QxxJEDEC_ID（制造商、类型、容量）
参    数 ： 无
返 回 值 ： temp[0] ---- JEDEC_ID
*************************************************/
uint32_t W25Qxx_Read_JEDECID(void)
{
	uint32_t temp[4] = {0};

    W25Q_CS_0();
	
	SPI_Flash_SendByte(W25Q_JEDEC_ID);
	temp[1] = SPI_Flash_SendByte(W25Q_DUMMY_BYTE);		// 制造商
	temp[2] = SPI_Flash_SendByte(W25Q_DUMMY_BYTE);		// 类型
	temp[3] = SPI_Flash_SendByte(W25Q_DUMMY_BYTE);		// 容量
	temp[0] = (temp[1] << 16) | (temp[2] << 8) | temp[3];
	
    W25Q_CS_1();
	
	return temp[0];
}


/************************************************
函数名称 ： W25Qxx_Read_Manufacturer_ID
功    能 ： 读 W25Qxx制造商 ID
参    数 ： 无
返 回 值 ： id_num ---- 制造商 ID
*************************************************/
uint16_t W25Qxx_Read_Manufacturer_ID(void)
{
	uint16_t id_num = 0;

    W25Q_CS_0();
	
	SPI_Flash_SendByte(W25Q_MANUFACTURER_ID);
	SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	SPI_Flash_SendByte(0x00);
	id_num |= SPI_Flash_SendByte(W25Q_DUMMY_BYTE) << 8;
	id_num |= SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	
    W25Q_CS_1();
	
	return id_num;
}

/************************************************
函数名称 ： W25Qxx_Read_DeviceID
功    能 ： 读 W25Qxx设备 ID
参    数 ： 无
返 回 值 ： id_num ---- 设备 ID
*************************************************/
uint8_t W25Qxx_Read_DeviceID(void)
{
	uint8_t id_num = 0;

    W25Q_CS_0();
	
	SPI_Flash_SendByte(W25Q_DEVICE_ID);
	SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	id_num = SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
	
    W25Q_CS_1();
	
	return id_num;
}

/************************************************
函数名称 ： W25Qxx_Page_Program
功    能 ： W25Qxx页编程（调用本函数写入数据前需要先擦除扇区）
参    数 ： pBuffer ---- 数据
			Address ---- 地址
			Len ---- 长度
返 回 值 ： 无
*************************************************/
void W25Qxx_Page_Program( uint8_t *pBuffer, uint32_t Address, uint16_t Len )
{
	W25Qxx_Write_Enable();
	
    W25Q_CS_0();
	
	SPI_Flash_SendByte(W25Q_PAGE_PROGRAM);
	SPI_Flash_SendByte((Address & 0xFF0000) >> 16);
	SPI_Flash_SendByte((Address & 0xFF00) >> 8);
	SPI_Flash_SendByte(Address & 0xFF);
	
	if(Len > W25Q_PAGE_SIZE)
	{
		Len = W25Q_PAGE_SIZE;
		W25Q_DEBUG_PRINTF("W25Qxx Page Program data too large!\n"); 
	}
	while(Len--)
	{
		SPI_Flash_SendByte(*pBuffer);
		pBuffer++;
	}
	
    W25Q_CS_1();
	
	W25Qxx_Busy_Wait();
}


/************************************************
函数名称 ： W25Qxx_Write_Flash
功    能 ： 写 W25Qxx闪存数据（调用本函数写入数据前需要先擦除扇区）
参    数 ： pBuffer ---- 数据
			Address ---- 地址
			Len ---- 长度
返 回 值 ： 无
*************************************************/
void W25Qxx_Write_Flash( uint8_t *pBuffer, uint32_t Address, uint16_t Len )
{
	uint8_t NumOfPage = 0, NumOfSingle = 0;
	uint8_t Addr = 0, count = 0, temp = 0;
	
	/* mod运算求余，若 Address是 W25Q_PAGE_SIZE整数倍，运算结果 Addr值为 0 */
	Addr = Address % W25Q_PAGE_SIZE;
	
	/* 差count个数据值，刚好可以对齐到页地址 */
	count = W25Q_PAGE_SIZE - Addr;
	
	/* 计算出要写多少整数页 */
	NumOfPage =  Len / W25Q_PAGE_SIZE;
	
	/* 计算出剩余不满一页的字节数 */
	NumOfSingle = Len % W25Q_PAGE_SIZE;
	
	/* Addr = 0,则 Address刚好按页对齐 */
	if(0 == Addr)
	{
		/* Len <= W25Q_PAGE_SIZE */
		if(0 == NumOfPage) 
		{
			/* 不到一页 or 刚好一页 */
			W25Qxx_Page_Program(pBuffer, Address, Len);
		}
		else /* Len > W25Q_PAGE_SIZE */
		{ 
			/* 先把整数页的都写了 */
			while(NumOfPage--)
			{
				W25Qxx_Page_Program(pBuffer, Address, W25Q_PAGE_SIZE);
				Address += W25Q_PAGE_SIZE;
				pBuffer += W25Q_PAGE_SIZE;
			}
			/* 若有多余的不满一页的数据，下一页把它写完 */
			if(NumOfSingle != 0)
			{
				W25Qxx_Page_Program(pBuffer, Address, NumOfSingle);
			}
		}
	}
	/* 若地址与 W25Q_PAGE_SIZE不对齐  */
	else 
	{
		/* Len < W25Q_PAGE_SIZE */
		if(0 == NumOfPage)
		{
			/* 当前页剩余的 count个位置比 NumOfSingle小，一页写不完 */
			if(NumOfSingle > count) 
			{
				/* 先写满当前页 */
				W25Qxx_Page_Program(pBuffer, Address, count);
						
				temp = NumOfSingle - count;
				Address += count;
				pBuffer += count;
				/* 再写剩余的数据 */
				W25Qxx_Page_Program(pBuffer, Address, temp);
			}
			else /* 当前页剩余的 count个位置能写完 NumOfSingle个数据 */
			{
				W25Qxx_Page_Program(pBuffer, Address, Len);
			}
		}
		else /* Len > W25Q_PAGE_SIZE */
		{
			/* 地址不对齐多出的 count分开处理，不加入这个运算 */
			Len -= count;
			NumOfPage =  Len / W25Q_PAGE_SIZE;
			NumOfSingle = Len % W25Q_PAGE_SIZE;
			
			if(count != 0)
			{
				/* 先写完count个数据，为的是让下一次要写的地址对齐 */
				W25Qxx_Page_Program(pBuffer, Address, count);
					
				/* 接下来就重复地址对齐的情况 */
				Address +=  count;
				pBuffer += count;
			}
			
			/* 把整数页都写了 */
			while(NumOfPage--)
			{
				W25Qxx_Page_Program(pBuffer, Address, W25Q_PAGE_SIZE);
				Address +=  W25Q_PAGE_SIZE;
				pBuffer += W25Q_PAGE_SIZE;
			}
			/* 若有多余的不满一页的数据，把它写完*/
			if(NumOfSingle != 0)
			{
				W25Qxx_Page_Program(pBuffer, Address, NumOfSingle);
			}
		}
	}
}

/************************************************
函数名称 ： W25Qxx_Read_Flash
功    能 ： 读 W25Qxx闪存数据
参    数 ： pBuffer ---- 数据
			Address ---- 地址
			Len ---- 长度
返 回 值 ： 无
*************************************************/
void W25Qxx_Read_Flash( uint8_t *pBuffer, uint32_t Address, uint16_t Len )
{
	
    W25Q_CS_0();
	
	SPI_Flash_SendByte(W25Q_READ_DATA);
	SPI_Flash_SendByte((Address & 0xFF0000) >> 16);
	SPI_Flash_SendByte((Address & 0xFF00) >> 8);
	SPI_Flash_SendByte(Address & 0xFF);
	
	/* 读取数据 */
	while(Len--)
	{
		*pBuffer = SPI_Flash_SendByte(W25Q_DUMMY_BYTE);
		pBuffer++;
	}
	
    W25Q_CS_1();
}

/************************************************
函数名称 ： W25Qxx_Sector_Erase
功    能 ： FLASH扇区擦除
参    数 ： Address ---- 擦除地址
返 回 值 ： 无
*************************************************/
void W25Qxx_Sector_Erase( uint32_t Address )
{
	W25Qxx_Write_Enable();

    W25Q_CS_0();

	SPI_Flash_SendByte(W25Q_SECTOR_ERASE);
	SPI_Flash_SendByte((Address & 0xFF0000) >> 16);
	SPI_Flash_SendByte((Address & 0xFF00) >> 8);
	SPI_Flash_SendByte(Address & 0xFF);

    W25Q_CS_1();
	
	W25Qxx_Busy_Wait();
}

/************************************************
函数名称 ： W25Qxx_Chip_Erase
功    能 ： FLASH整片擦除(为了安全起见，若要调用，请先调用 W25Qxx_Write_Enable函数)
参    数 ： 无
返 回 值 ： 无
*************************************************/
void W25Qxx_Chip_Erase(void)
{
    W25Q_CS_0();
	
	SPI_Flash_SendByte(W25Q_CHIP_ERASE);
	
    W25Q_CS_1();
	
	W25Qxx_Busy_Wait();
}

/************************************************
函数名称 ： W25Qxx_Write_Enable
功    能 ： W25Qxx写使能
参    数 ： 无
返 回 值 ： 无
*************************************************/
void W25Qxx_Write_Enable(void)
{
	uint8_t flash_status = 0;

    W25Q_CS_0();
    SPI_Flash_SendByte(W25Q_WRITE_ENABLE);
    W25Q_CS_1();
		
    W25Q_CS_0();
	/* 等待写使能位置 1 */
	do
	{
		flash_status = SPI_Flash_SendByte(W25Q_STATUS_REG1);
	}while(!(flash_status & BIT_WEL));
    W25Q_CS_1();
}

/************************************************
函数名称 ： W25Qxx_Write_Disable
功    能 ： W25Qxx写失能
参    数 ： 无
返 回 值 ： 无
*************************************************/
void W25Qxx_Write_Disable(void)
{
	uint8_t flash_status = 0;

    W25Q_CS_0();
    SPI_Flash_SendByte(W25Q_WRITE_DISABLE);
    W25Q_CS_1();
	
    W25Q_CS_0();
	/* 等待写使能清 0 */
	do
	{
		flash_status = SPI_Flash_SendByte(W25Q_STATUS_REG1);
	}while(!(flash_status & BIT_WEL));
    W25Q_CS_1();

}

/************************************************
函数名称 ： W25Qxx_Power_Down
功    能 ： W25Qxx掉电
参    数 ： 无
返 回 值 ： 无
*************************************************/
void W25Qxx_Power_Down(void)
{
    W25Q_CS_0();
    SPI_Flash_SendByte(W25Q_POWER_DOWN);
    W25Q_CS_1();
}

/************************************************
函数名称 ： W25Qxx_Release_PowerDown
功    能 ： W25Qxx唤醒
参    数 ： 无
返 回 值 ： 无
*************************************************/
void W25Qxx_Release_PowerDown(void)
{
    W25Q_CS_0();
    SPI_Flash_SendByte(W25Q_RELEASE_POWER_DOWN);
    W25Q_CS_1();
}

/***********************************************************/


#if (0 == _CPOL && 0 == _CPHA) /* ----- MODE 1 ----- */
/************************************************
函数名称 ： SPI_SendByte
功    能 ： SPI写读一个字节
参    数 ： Byte ---- 数据
返 回 值 ： Byte ---- 数据
*************************************************/
static uint8_t SPI_SendByte( uint8_t Byte )
{
	uint8_t i;

	for(i = 0;i < 8;i++)
	{
		SPI_SCK_0();
		SPI_Delay();       // 空等待
		// 下降沿 写数据 
		if(Byte & 0x80)
		{
			SPI_MOSI_1();
		}
		else
		{
			SPI_MOSI_0();
		}
		

		Byte <<= 1;
		SPI_Delay();       // 空等待
		SPI_SCK_1();
		SPI_Delay();       // 空等待 
		if(SPI_MISO_READ())
		{
			Byte |= 0x01;
		}
	}

	SPI_SCK_0();

	return Byte;
}
 

#elif (0 == _CPOL && 1 == _CPHA) /* ----- MODE 1 ----- */

/************************************************
函数名称 ： SPI_SendByte
功    能 ： SPI写读一个字节
参    数 ： Byte ---- 数据
返 回 值 ： Byte ---- 数据
*************************************************/
static uint8_t SPI_SendByte( uint8_t Byte )
{
	uint8_t i;

    SPI_SCK_0();

	for(i = 0;i < 8;i++)
	{
		SPI_SCK_1();
		SPI_Delay();       // 空等待
		// 下降沿 写数据 
		if(Byte & 0x80)
		{
			SPI_MOSI_1();
		}
		else
		{
			SPI_MOSI_0();
		}
		

		Byte <<= 1;
		SPI_Delay();       // 空等待
		SPI_SCK_0();
		SPI_Delay();       // 空等待 
		if(SPI_MISO_READ())
		{
			Byte |= 0x01;
		}
	}

	return Byte;
}
 

#elif (1 == _CPOL && 0 == _CPHA) /* ----- MODE 2 ----- */
/************************************************
函数名称 ： SPI_SendByte
功    能 ： SPI写读一个字节
参    数 ： Byte ---- 数据
返 回 值 ： Byte ---- 数据
*************************************************/
static uint8_t SPI_SendByte( uint8_t Byte )
{
	uint8_t i;
	for(i = 0;i < 8;i++)
	{
		SPI_SCK_1();
		SPI_Delay();       // 空等待
		// 下降沿 写数据 
		if(Byte & 0x80)
		{
			SPI_MOSI_1();
		}
		else
		{
			SPI_MOSI_0();
		}
		

		Byte <<= 1;
		SPI_Delay();       // 空等待
		SPI_SCK_0();
		SPI_Delay();       // 空等待 
		if(SPI_MISO_READ())
		{
			Byte |= 0x01;
		}
	}
    SPI_SCK_1();
	return Byte;
}
 

#elif (1 == _CPOL && 1 == _CPHA) /* ----- MODE 3 ----- */
/************************************************
函数名称 ： SPI_SendByte
功    能 ： SPI写读一个字节
参    数 ： Byte ---- 数据
返 回 值 ： Byte ---- 数据
*************************************************/
static uint8_t SPI_SendByte( uint8_t Byte )
{
	uint8_t i;

	SPI_SCK_1();
	
	for(i = 0;i < 8;i++)
	{
		SPI_SCK_0();
		SPI_Delay();       // 空等待
		// 下降沿 写数据 
		if(Byte & 0x80)
		{
			SPI_MOSI_1();
		}
		else
		{
			SPI_MOSI_0();
		}

		Byte <<= 1;
		SPI_Delay();       // 空等待
		SPI_SCK_1();
		SPI_Delay();       // 空等待 
		if(SPI_MISO_READ())
		{
			Byte |= 0x01;
		}
		
	}
	return Byte;
}
 

 
#endif /* SPI MODE */



// 调用
// HAL_Delay_u(1, 72);//延时1us, 时钟为72MHz
static void SPI_Delay(void)
{
    HAL_Delay_us(WAIT_TIME,168);
}
